Skip to main content

libobs_simple\sources\linux\sources/
linux_general_window_capture.rs

1use libobs_wrapper::{
2    data::ObsObjectBuilder,
3    runtime::ObsRuntime,
4    sources::ObsSourceBuilder,
5    utils::{ObjectInfo, ObsError, ObsString, PlatformType},
6};
7
8use crate::sources::{
9    linux::{
10        pipewire::{ObsPipeWireSourceRef, PipeWireWindowCaptureSourceBuilder},
11        XCompositeInputSource, XCompositeInputSourceBuilder,
12    },
13    ObsEither, ObsEitherSource,
14};
15
16pub struct LinuxGeneralWindowCaptureBuilder {
17    underlying_builder: ObsEither<XCompositeInputSourceBuilder, PipeWireWindowCaptureSourceBuilder>,
18}
19
20impl ObsObjectBuilder for LinuxGeneralWindowCaptureBuilder {
21    fn new<T: Into<ObsString> + Send + Sync>(name: T, runtime: ObsRuntime) -> Result<Self, ObsError>
22    where
23        Self: Sized,
24    {
25        let underlying_builder = match runtime.get_platform()? {
26            PlatformType::X11 => ObsEither::Left(XCompositeInputSourceBuilder::new(name, runtime)?),
27            PlatformType::Wayland => {
28                ObsEither::Right(PipeWireWindowCaptureSourceBuilder::new(name, runtime)?)
29            }
30            PlatformType::Invalid => {
31                return Err(ObsError::PlatformInitError(
32                    "No platform could be found to create the source on.".to_string(),
33                ))
34            }
35        };
36
37        Ok(Self { underlying_builder })
38    }
39
40    fn runtime(&self) -> &ObsRuntime {
41        match &self.underlying_builder {
42            ObsEither::Left(builder) => builder.runtime(),
43            ObsEither::Right(builder) => builder.runtime(),
44        }
45    }
46
47    fn get_name(&self) -> ObsString {
48        match &self.underlying_builder {
49            ObsEither::Left(builder) => builder.get_name(),
50            ObsEither::Right(builder) => builder.get_name(),
51        }
52    }
53
54    fn object_build(self) -> Result<ObjectInfo, ObsError>
55    where
56        Self: Sized,
57    {
58        match self.underlying_builder {
59            ObsEither::Left(builder) => builder.object_build(),
60            ObsEither::Right(builder) => builder.object_build(),
61        }
62    }
63
64    fn get_settings(&self) -> &libobs_wrapper::data::ObsData {
65        match &self.underlying_builder {
66            ObsEither::Left(builder) => builder.get_settings(),
67            ObsEither::Right(builder) => builder.get_settings(),
68        }
69    }
70
71    fn get_settings_updater(&mut self) -> &mut libobs_wrapper::data::ObsDataUpdater {
72        match &mut self.underlying_builder {
73            ObsEither::Left(builder) => builder.get_settings_updater(),
74            ObsEither::Right(builder) => builder.get_settings_updater(),
75        }
76    }
77
78    fn get_hotkeys(&self) -> &libobs_wrapper::data::ObsData {
79        match &self.underlying_builder {
80            ObsEither::Left(builder) => builder.get_hotkeys(),
81            ObsEither::Right(builder) => builder.get_hotkeys(),
82        }
83    }
84
85    fn get_hotkeys_updater(&mut self) -> &mut libobs_wrapper::data::ObsDataUpdater {
86        match &mut self.underlying_builder {
87            ObsEither::Left(builder) => builder.get_hotkeys_updater(),
88            ObsEither::Right(builder) => builder.get_hotkeys_updater(),
89        }
90    }
91
92    fn get_id() -> ObsString {
93        ObsString::from("linux_general_window_capture")
94    }
95}
96
97pub type LinuxGeneralWindowCaptureSourceRef =
98    ObsEitherSource<XCompositeInputSource, ObsPipeWireSourceRef>;
99
100impl ObsSourceBuilder for LinuxGeneralWindowCaptureBuilder {
101    type T = LinuxGeneralWindowCaptureSourceRef;
102
103    fn build(self) -> Result<Self::T, ObsError>
104    where
105        Self: Sized,
106    {
107        match self.underlying_builder {
108            ObsEither::Left(builder) => {
109                let source = builder.build()?;
110                Ok(ObsEitherSource::Left(source))
111            }
112            ObsEither::Right(builder) => {
113                let source = builder.build()?;
114                Ok(ObsEitherSource::Right(source))
115            }
116        }
117    }
118}
119
120impl LinuxGeneralWindowCaptureBuilder {
121    /// Set the PipeWire restore token, which will be used to re-establish the same selection the
122    /// user did previously.
123    /// # Display Server
124    /// PipeWire only
125    pub fn set_restore_token(mut self, token: &str) -> Self {
126        self.underlying_builder = match self.underlying_builder {
127            ObsEither::Left(builder) => ObsEither::Left(builder),
128            ObsEither::Right(builder) => {
129                ObsEither::Right(builder.set_restore_token(token.to_string()))
130            }
131        };
132
133        self
134    }
135
136    /// # Display Server
137    /// All supported display servers
138    pub fn set_show_cursor(mut self, show: bool) -> Self {
139        self.underlying_builder = match self.underlying_builder {
140            ObsEither::Left(builder) => ObsEither::Left(builder.set_show_cursor(show)),
141            ObsEither::Right(builder) => ObsEither::Right(builder.set_show_cursor(show)),
142        };
143
144        self
145    }
146
147    /// Set the window to capture (window ID as string)
148    /// # Display Server
149    /// XComposite (X11) only
150    pub fn set_capture_window(mut self, capture_window: &str) -> Self {
151        self.underlying_builder = match self.underlying_builder {
152            ObsEither::Left(builder) => {
153                ObsEither::Left(builder.set_capture_window(capture_window.to_string()))
154            }
155            ObsEither::Right(builder) => ObsEither::Right(builder),
156        };
157
158        self
159    }
160
161    /// Crop from top (in pixels)
162    /// # Display Server
163    /// XComposite (X11) only
164    pub fn set_cut_top(mut self, cut_top: i64) -> Self {
165        self.underlying_builder = match self.underlying_builder {
166            ObsEither::Left(builder) => ObsEither::Left(builder.set_cut_top(cut_top)),
167            ObsEither::Right(builder) => ObsEither::Right(builder),
168        };
169
170        self
171    }
172
173    /// Crop from left (in pixels)
174    /// # Display Server
175    /// XComposite (X11) only
176    pub fn set_cut_left(mut self, cut_left: i64) -> Self {
177        self.underlying_builder = match self.underlying_builder {
178            ObsEither::Left(builder) => ObsEither::Left(builder.set_cut_left(cut_left)),
179            ObsEither::Right(builder) => ObsEither::Right(builder),
180        };
181
182        self
183    }
184
185    /// Crop from right (in pixels)
186    /// # Display Server
187    /// XComposite (X11) only
188    pub fn set_cut_right(mut self, cut_right: i64) -> Self {
189        self.underlying_builder = match self.underlying_builder {
190            ObsEither::Left(builder) => ObsEither::Left(builder.set_cut_right(cut_right)),
191            ObsEither::Right(builder) => ObsEither::Right(builder),
192        };
193
194        self
195    }
196
197    /// Crop from bottom (in pixels)
198    /// # Display Server
199    /// XComposite (X11) only
200    pub fn set_cut_bot(mut self, cut_bot: i64) -> Self {
201        self.underlying_builder = match self.underlying_builder {
202            ObsEither::Left(builder) => ObsEither::Left(builder.set_cut_bot(cut_bot)),
203            ObsEither::Right(builder) => ObsEither::Right(builder),
204        };
205
206        self
207    }
208
209    /// Include window border/decorations
210    /// # Display Server
211    /// XComposite (X11) only
212    pub fn set_include_border(mut self, include_border: bool) -> Self {
213        self.underlying_builder = match self.underlying_builder {
214            ObsEither::Left(builder) => ObsEither::Left(builder.set_include_border(include_border)),
215            ObsEither::Right(builder) => ObsEither::Right(builder),
216        };
217
218        self
219    }
220
221    /// Exclude alpha channel (disable transparency)
222    /// # Display Server
223    /// XComposite (X11) only
224    pub fn set_exclude_alpha(mut self, exclude_alpha: bool) -> Self {
225        self.underlying_builder = match self.underlying_builder {
226            ObsEither::Left(builder) => ObsEither::Left(builder.set_exclude_alpha(exclude_alpha)),
227            ObsEither::Right(builder) => ObsEither::Right(builder),
228        };
229
230        self
231    }
232}